import sys
import os

sys.path.append(os.getcwd())

from codesecurity.feature.objects import Ast,AstNode,CommonFeatureSet
from codesecurity.feature.property_graph import *
from codesecurity.feature.node_type_const import JSNodeTypes
from codesecurity.utils.pretty_print import percent

import codesecurity.feature.objects as data_objects

from collections import Counter

def printlist(list):
    for i in list:
        print(i)

    
def search_identifier_declaration_js(features:CommonFeatureSet,image_builder:AstImageBuilder):
    js_types=JSNodeTypes()

    choose_type=[e.node_type for e in js_types.declaration_types()]

    image_builder=AstImageBuilder(features.ast_object)

    nodes=features.search_nodes(choose_type)
    
    children=[image_builder.node_out(node) for node in nodes]
    
    return nodes,children

def search_property_declaration_js(features:CommonFeatureSet,image_builder:AstImageBuilder):
    choose_type='object'
    
    nodes=features.search_nodes(choose_type)
    
    node_parents=[image_builder.node_in(node) for node in nodes]
    children_group=[search_pair_js(e,image_builder) for e in nodes]
    
    return nodes,node_parents,children_group

def search_pair_js(ast_node:AstNode,image_builder:AstImageBuilder):    
    children=image_builder.node_out(ast_node)
    
    pairs=[]
    for child in children:
        if child.ast_type=='pair':
            pairs.append(child)
    
    
    return ast_node,pairs

def search_assignment_js(features:CommonFeatureSet,image_builder:AstImageBuilder):
    choose_type=['assignment_expression','augmented_assignment_expression']
    nodes=features.search_nodes(choose_type)
    nodes_children=[image_builder.node_out(node) for node in nodes]
    
    # for i in range(len(nodes_children)):
    #     left=nodes_children[i][0]
    #     right=nodes_children[i][-1]
        
    #     left_children=[left] if left.ast_type=='identifier' else image_builder.node_out(left)
    #     right_children=[right] if right.ast_type=='identifier' else image_builder.node_out(right)
        
    #     nodes_children[i]=[left_children,right_children]

    return nodes,nodes_children

def search_identifier_dependency(features:CommonFeatureSet,image_builder:AstImageBuilder):
    js_types=JSNodeTypes()

    nodes,node_children=search_identifier_declaration_js(features,image_builder)

    identifiers={}
    for node,children in zip(nodes,node_children):
        if node.ast_type not in identifiers:
            identifiers[node.ast_type]=[]
        if node.ast_type=='function_declaration':
            identifiers[node.ast_type].append(children[1])
        elif node.ast_type=='variable_declaration':
            declarator='variable_declarator'
            declarator_nodes=[e for e in children if e.ast_type==declarator]
            for e in declarator_nodes:
                identifiers[node.ast_type].extend([search_first_identifier_in_children_js(e,image_builder)])
        else:
            identifiers[node.ast_type].extend([search_first_identifier_in_children_js(node,image_builder)])
    
    dependency=[]
    
    
    return identifiers

def search_all_string_js(features:CommonFeatureSet,image_builder:AstImageBuilder):
    js_types=JSNodeTypes()

    choose_type=["string"]

    nodes=features.search_nodes(choose_type)
    
    return nodes

def search_all_number_js(features:CommonFeatureSet,image_builder:AstImageBuilder):
    js_types=JSNodeTypes()

    choose_type=["number"]

    nodes=features.search_nodes(choose_type)
    
    return nodes

def search_all_call_function_js(features:CommonFeatureSet,image_builder:AstImageBuilder):
    js_types=JSNodeTypes()

    choose_type=["call_expression"]

    nodes=features.search_nodes(choose_type)
    group_children=[image_builder.node_out(e) for e in nodes]
    
    return [e[0] for e in group_children]


test_file=os.getcwd()+r'/test_data/sample.js'


features=CommonFeatureSet.from_file(test_file)
image_builder=AstImageBuilder(features.ast_object)

def test_func_api_extract():
    identifiers=JsValueDependency.api_call_table(features.ast_object,image_builder)
    example_counter=Counter()
    for key in identifiers:
        example_counter[identifiers[key]]+=1
        print("api: ",key,identifiers[key])
        #print(normal_func[func])
        #print("----")
        
    for key in example_counter:
        print("status: ",key,example_counter[key],percent(example_counter[key]/len(features.ast_object.nodes)))
        print("----")
        

def test_func_call_extract():
    normal_nodes, anomy_nodes=JsNodeSearch.search_func_binding_js(features.ast_object,image_builder)
    examples={}
    example_counter=Counter()
    for func,identifier in anomy_nodes:
        if identifier.ast_type not in examples:
            examples[identifier.ast_type]=[]
        examples[identifier.ast_type]=identifier
        
        example_counter[identifier.ast_type]+=1
    
    for key in examples:
        print("status: ",key,example_counter[key])
        print(examples[key])
        #print(normal_func[func])
        print("----")

def test_const_value_extract():
    identifiers=JsValueDependency.const_table(features.ast_object)
    example_counter=Counter()
    for key in identifiers:
        example_counter[identifiers[key]]+=1
        print("api: ",key,identifiers[key])
        #print(normal_func[func])
        #print("----")
        
    for key in example_counter:
        print("status: ",key,example_counter[key],percent(example_counter[key]/len(features.ast_object.nodes)))
        print("----")

#identifiers=search_identifier_dependency(features,image_builder)

#print(sum([len(e) for e in identifiers.values()]))

# 

# a=features.search_nodes(['function_declaration'])[1]
# child=image_builder.node_out(a)[0]
# child_parent=image_builder.node_in(child)[0]
# print(a)
# print(child)
# print(child_parent)
# print(image_builder.node_in(child_parent)[0])
#print(child==image_builder.node_in(child)[0])
#printlist([e.ast_value for e in a])
#printlist([[k.ast_value for k in image_builder.node_in(e)]+[e.ast_value] for e in a])

#test_func_api_extract()
#test_func_call_extract()
test_const_value_extract()
# assignment_stats=JsNodeSearch.search_func_declaration_js(features.ast_object,image_builder)
# for stats in zip(*assignment_stats):
#     node,children,ret=stats
    
#     identifier,parameters,block=children
    
#     #print([features.nodes[e].ast_type for e in image_builder.walk2root(node)])
#     # print(node.ast_type)
#     #if in_node is None or in_node.ast_type !='identifier':
    
#     #core_identifier_left=JsNodeSearch.search_core_identifier_in_children_js(node,image_builder)
#     #core_identifier_right=JsNodeSearch.search_core_identifier_in_children_js(children,image_builder)
#     #core_identifier_right=JsNodeSearch.search_core_identifier_in_children_js(children[-1],image_builder)
    
#     # print(node.ast_value)
#     # print(children,[e.ast_type for e in children if e is not None])
#     # print(ret)
#     #print([e.ast_type for e in core_identifier_left if e is not None])
#     #print([e.ast_type for e in core_identifier_right if e is not None])
#     print(node)
#     print(identifier,parameters,block)
#     print('--')
    
#     #print([e.ast_type for e in children[1]])
    
#     print("----")
#printlist(nodes)

# nodes,node_parents,node_children=search_property_declaration_js(features,image_builder)
# for node,parent,children in zip(nodes,node_parents,node_children):
#     # if node.ast_type=='variable_declaration':
#     #     print(node.ast_type)
#     #     print([e.ast_type for e in children])
#     #     print("----")
#     print(node.ast_type)
#     print([e.ast_type for e in parent])
#     printlist(children)
#     print(parent[0].ast_value)
#     print("----") 
    
# print(len(node_children))


#search_identifier_dependency(test_file)
# nodes,node_identifiers=search_identifier_declaration_js(test_file)
# for node,children in zip(nodes,node_identifiers):
#     print(node.ast_type)
#     print(children)
#     print("----") 
    
# all_in_type=js_types.children_with_type(choose_type)
# all_in_type+=js_types.field_with_type(choose_type)
# all_in_type=set(all_in_type)
# for node in nodes:
#     in_set=set([e.ast_type for e in image_builder.node_in(node)])
#     print(list(in_set))
#     print(in_set.issubset(all_in_type))
    
# for e in all_in_type:
#     print(e)

# for node in nodes:
#     print(node.ast_value)


# paths=random_walk(features)

# path_text=list_walk_path(paths,features)

# counter=Counter()

# anchor_nodes=get_anchor_node_js(features)
# image_builder=AstImageBuilder(features.ast_object)


# neighbor_indexs=set()

# for node in anchor_nodes:
#     neighbor_indexs.update(get_anchor_node_variable(node,image_builder))

# identifier_counter=search_identifier_js(image_builder.ast_object)

# identifier_counter={k:len(v) for k,v in identifier_counter.items()}
# identifier_counter=sorted(identifier_counter.items(),key=lambda x:x[1],reverse=True)

# print(identifier_counter)
# print(sum([count for _,count in identifier_counter]))

#printlist([(features.nodes[index].ast_type,features.nodes[index].ast_value) for index in neighbor_indexs])
    # for index in neighbor_indexs:
    #     printlist(list_child_node(image_builder,index))
    #break

# for node in anchor_nodes:
#     neighbors=get_anchor_node_neighbor(node,image_builder)
#     counter.update(neighbors)

# core_nodes=[(features.nodes[index],count) for index,count in counter.most_common(15)]

# printlist([(e.ast_value,count) for e,count in core_nodes])